%{
#include <stdio.h>
int initial_column_count = 0;
int extra_error_shown  = 0;
int temp_element_count = 0;
extern int lineno;
%}

%start program

%token MAIN DOLLAR_SIGN EXCLAMATION VERTICAL_LINE R_CURLYBRACKET RETURN FLOAT_LITERAL L_PARANTHESIS GREATER DEFINE COLON SEMICOLON ASTERIKS R_SQUAREBRACKET IDENTIFIER BOOLEAN_LITERAL UNARY_MINUS_SIGN  LESS WHILE STRING_LITERAL INTEGER_LITERAL R_PARANTHESIS L_CURLYBRACKET COMMA MINUS EQUALS SOLIDUS FOR PLUS L_SQUAREBRACKET IF ELSE DO BREAK CONTINUE PERCENT AMPERSAND QUESTION TILDA DOT QUOTE NUMBER_SIGN COMMENT  
%token DISPLAY ONES ZEROS IDENTITY ROWS COLUMNS TRANSPOSE INVERSE 
%right LESS EXCLAMATION GREATER PLUS MINUS ASTERISK SOLIDUS
%right EQUALS UNARY_MINUS_SIGN

%%
statement_list : statement | statement_list statement;

program :  MAIN  L_CURLYBRACKET statement_list R_CURLYBRACKET;

statement : return_statement SEMICOLON
	    | variable_declaration_statement SEMICOLON
	    | code_block_statement
	    | while_statement
	    | for_statement
	    | if_statement
	    | function_declaration_statement
	    | function_invocation_statement;
		| BREAK | CONTINUE | COMMENT;


if_statement : IF L_PARANTHESIS expression R_PARANTHESIS L_CURLYBRACKET  statement_list   R_CURLYBRACKET 
			  |IF L_PARANTHESIS expression R_PARANTHESIS L_CURLYBRACKET statement_list R_CURLYBRACKET ELSE L_CURLYBRACKET statement_list R_CURLYBRACKET; 

for_statement: FOR L_PARANTHESIS for_header R_PARANTHESIS code_block_statement;
for_header : 	SEMICOLON SEMICOLON
		| SEMICOLON SEMICOLON  variable_declaration_statement
		| SEMICOLON factor SEMICOLON
		| variable_declaration_statement SEMICOLON SEMICOLON  variable_declaration_statement
		| variable_declaration_statement SEMICOLON factor SEMICOLON
		| variable_declaration_statement SEMICOLON factor SEMICOLON  variable_declaration_statement;

while_statement: WHILE L_PARANTHESIS factor R_PARANTHESIS statement;

code_block_statement : L_CURLYBRACKET statement_list  R_CURLYBRACKET;

return_statement: RETURN
		| RETURN  expression ;

function_declaration_statement : NUMBER_SIGN  DEFINE  IDENTIFIER L_PARANTHESIS argument_list R_PARANTHESIS L_CURLYBRACKET  statement_list R_CURLYBRACKET;
argument_list : expression {temp_element_count++; }
				| argument_list COMMA expression {temp_element_count++;};

function_invocation_statement : function_call_expression  SEMICOLON;
		
variable_declaration_statement : variable_declaration | matrix_element_assignment | submatrix_assignment;
variable_declaration :  variable EQUALS expression;

matrix_element_assignment : variable  L_SQUAREBRACKET matrix_vector R_SQUAREBRACKET EQUALS expression;
matrix_vector : expression COMMA expression;
	
matrix_element: variable  L_SQUAREBRACKET matrix_vector R_SQUAREBRACKET;
				
submatrix : variable L_SQUAREBRACKET matrix_interval R_SQUAREBRACKET;

submatrix_assignment : variable L_SQUAREBRACKET matrix_interval R_SQUAREBRACKET EQUALS expression;
matrix_interval: matrix_vector COLON matrix_vector;

expression: expression PLUS term | expression MINUS term
	    | term; 

term: term ASTERIKS factor | term SOLIDUS factor
		| factor; 

unary_minus : UNARY_MINUS_SIGN  factor;

factor: L_PARANTHESIS expression R_PARANTHESIS
	| unary_minus
	| literal_expression
	| function_call_expression
	| logical_expression
	| testing_expression
	| submatrix
	| matrix_element
	| variable;

literal_expression : matrix | integer | float | string |boolean;

matrix : {initial_column_count=0;extra_error_shown=0;temp_element_count=0;} L_SQUAREBRACKET row_list R_SQUAREBRACKET;
row_list : row { initial_column_count = temp_element_count; } |
			row_list VERTICAL_LINE { temp_element_count = 0;}  row 
			{ if (temp_element_count != initial_column_count){if(extra_error_shown==0){printf("\nSYNTAX ERROR: Different number of columns recognized in matrix located at line %d.(+10pts)", lineno); extra_error_shown=1;}}};
row : argument_list;

integer: INTEGER_LITERAL;
float : FLOAT_LITERAL;
string : STRING_LITERAL;
boolean : BOOLEAN_LITERAL;

function_call_expression: IDENTIFIER L_PARANTHESIS argument_list R_PARANTHESIS
			  |   built_in_functions;

built_in_functions : f_display | f_ones | f_zeros | f_identity | f_rows | f_columns | f_transpose | f_inverse;
f_display : DISPLAY L_PARANTHESIS argument_list R_PARANTHESIS   ;
f_ones : ONES L_PARANTHESIS argument_list R_PARANTHESIS ;
f_zeros : ZEROS L_PARANTHESIS argument_list R_PARANTHESIS ;
f_identity : IDENTITY L_PARANTHESIS argument_list R_PARANTHESIS ;
f_rows : ROWS L_PARANTHESIS argument_list R_PARANTHESIS ;
f_columns : COLUMNS L_PARANTHESIS argument_list R_PARANTHESIS ;
f_transpose : TRANSPOSE L_PARANTHESIS argument_list R_PARANTHESIS ;
f_inverse : INVERSE L_PARANTHESIS argument_list R_PARANTHESIS ;

logical_expression: EXCLAMATION factor;

testing_expression: factor LESS  factor
		| factor GREATER factor
		| factor GREATER EQUALS factor
		| factor LESS EQUALS factor
		| factor EQUALS EQUALS  factor
		| factor EXCLAMATION EQUALS factor;

variable : DOLLAR_SIGN IDENTIFIER ;
%%
#include "lex.yy.c"

int yyerror(char *s) {
	printf ("%s at line %d\n", s, lineno);
	erroroccured = 1;
}

int main(){ 
	yyparse();
	if(erroroccured==0)printf("\nOK.\n");
	return 0;
}
